﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Reflection;
using log4net;
using NDesk.Options;

namespace Quiki.Console
{
    public class ConsoleApp
    {
        public ConsoleApp (string[] args, ICollection<IConsoleCommand> commands)
        {
            log4net.Config.XmlConfigurator.Configure();

            this.args = args;

            foreach (IConsoleCommand command in commands)
                AddCommand(command);
        }

        [SuppressMessage ("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
        public int Process ()
        {
            ShowBanner();

            try
            {
                if (args.Length == 0)
                {
                    ShowHelp();
                    return 0;
                }

                string commandName = args[0];

                if (commands.ContainsKey(commandName))
                {
                    IConsoleCommand command = commands[commandName];

                    List<string> remainingArgs = new List<string>(args);
                    remainingArgs.RemoveAt(0);

                    return command.Execute(remainingArgs);
                }
                else
                {
                    throw new ArgumentException(
                        String.Format(
                            CultureInfo.InvariantCulture,
                            "Unknown command: '{0}'",
                            commandName));
                }
            }
            catch (OptionException ex)
            {
                log.Error("ERROR:", ex);
                ShowHelp();
            }
            catch (ArgumentException ex)
            {
                log.Error ("ERROR:", ex);
                ShowHelp ();
            }
            catch (Exception ex)
            {
                log.Fatal("ERROR:", ex);
            }

            return 1;
        }

        private void AddCommand (IConsoleCommand command)
        {
            commands.Add(command.CommandName, command);
        }

        private static void ShowBanner()
        {
            FileVersionInfo version = FileVersionInfo.GetVersionInfo (
                Assembly.GetExecutingAssembly ().Location);
            log.InfoFormat("EEnvoyer.Console v{0}", version.FileVersion);
            log.Info (String.Empty);
        }

        [SuppressMessage ("Microsoft.Globalization", "CA1305:SpecifyIFormatProvider", MessageId = "log4net.ILog.InfoFormat(System.String,System.Object[])")]
        private void ShowHelp ()
        {
            log.InfoFormat ("USAGE: EEnvoyer.Console <command> <options>");
            log.InfoFormat ("-----------------------");
            log.InfoFormat ("LIST OF COMMANDS:");
            log.Info (String.Empty);

            foreach (IConsoleCommand command in commands.Values)
            {
                log.InfoFormat ("Command '{0}': {1}", command.CommandName, command.CommandDescription);
                log.Info (String.Empty);
                log.InfoFormat ("Options for '{0}':", command.CommandName);
                log.Info (String.Empty);
                command.ShowHelp ();
                log.Info (String.Empty);
            }
        }

        private readonly string[] args;
        private SortedDictionary<string, IConsoleCommand> commands = new SortedDictionary<string, IConsoleCommand>();
        private static readonly ILog log = LogManager.GetLogger (typeof(ConsoleApp));
    }
}